package com.wx.activitys.drp.service;

import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Encoder;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.UUID;

/**
 * DESCRIPTION:数字签名
 * AUTHOR: Qinlong
 * DATE: 2017/8/22
 */
public class DigitalSignature {

    public static final String PUBLIC_KEY = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJNdNJ5b/1pa05CpjXQcFEUFp3hqH6CEKFe+0yzlYX30kQzQ47DZun5oECXjO0TXCE8L/jSwIfo1b9F8ViL7dscCAwEAAQ==";
    //public static final String PRIVATE_KEY = "MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAk100nlv/WlrTkKmNdBwURQWneGofoIQoV77TLOVhffSRDNDjsNm6fmgQJeM7RNcITwv+NLAh+jVv0XxWIvt2xwIDAQABAkEAh/470OiVfozTMW1HXR+MlSXipv1IsplDobY4q/YDQnhC92EnCSLhLvxVNMghfNp9ztfR6htiFf9397MnvGPEAQIhAOxenwgEdWAf8SfnuTY8Ff6UydRlFL9zxL4OKZx653G/AiEAn5pEJoiXX7YcaLZRv2RVyM7BWPB3CGCkpeF7OiHvLPkCIBAIFuc3TjK31+Zp/BDmoGNE+i9yr6aQlo6BbWcUmvAHAiEAkwCY4tEOc9adpgi/lMRKixF8XnnleS7il/Lt+CZHUKkCIQChqk9biDo5qAiqZDNh4DgAhQ/0XeFLe/MxgDPTnFWwzQ==";
    public static final String PRIVATE_KEY = "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAhbjxXnbBh9m/YlrHAQJZJ0UTWPk4SkBxFg0L4uwz5yl8SupiyQOOLnZKERwXW7nPmxOQgM3xdJB63ujWLRJQuQIDAQABAkAWvQQOFBOEjjpE9zqvqT6Ptuc7UeWIerzACyfiRlftDpixbVDIO9ar7CaIy8jJAcgLMyURssZpK/c5QSmkbv0hAiEA4aFZ7RG4MRv0jl0juFPs0gW2kxChShz6H/dDLVv1M0sCIQCXuK3/PJwQ/pgY8pWlrJbAo5/g13XLRYXOYUxHGm0FiwIgX2HvexnHjPMtclWLeSv5bFu/7/HSzVrsnkDQJEfAo3sCIQCAbgA7sl6ZtCmj1JUAbRwfbWKEvV4k93DQxmP/PEtVCQIhAJRcTH7M0f7PbINSjXlzHj9jUkrUGJ8yNcLSwNqMBExp";

    /**
     * uuid：用户唯一标识号，同一个用户用户标识相同，长度不超过40
     * source：渠道（固定值），卡卡贷提供source ：jiahua
     * timestamp：时间戳
     * signature：数字签名
     * 签名算法使用RSA非对称加密算法。
     * 第三方客户端持有私钥，对数据加签。
     * 卡卡贷持有公钥，对数据验签。
     * 加签数据data：uuid+source+timestamp（用户唯一标识，渠道，时间戳）拼成的字符串，中间的特殊符号（+、=、/）需要转义成16进制
     * （java方法：URLEncoder.encode(signature,”utf-8”)）。
     * 测试公钥（长度512）：
     * MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJNdNJ5b/1pa05CpjXQcFEUFp3hqH6CEKFe+0yzlYX30kQzQ47DZun5oECXjO0TXCE8L/jSwIfo1b9F8ViL7dscCAwEAAQ==
     * 测试私钥（长度512）：
     * MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAk100nlv/WlrTkKmNdBwURQWneGofoIQoV77TLOVhffSRDNDjsNm6fmgQJeM7RNcITwv+NLAh+jVv0XxWIvt2xwIDAQABAkEAh/470OiVfozTMW1HXR+MlSXipv1IsplDobY4q/YDQnhC92EnCSLhLvxVNMghfNp9ztfR6htiFf9397MnvGPEAQIhAOxenwgEdWAf8SfnuTY8Ff6UydRlFL9zxL4OKZx653G/AiEAn5pEJoiXX7YcaLZRv2RVyM7BWPB3CGCkpeF7OiHvLPkCIBAIFuc3TjK31+Zp/BDmoGNE+i9yr6aQlo6BbWcUmvAHAiEAkwCY4tEOc9adpgi/lMRKixF8XnnleS7il/Lt+CZHUKkCIQChqk9biDo5qAiqZDNh4DgAhQ/0XeFLe/MxgDPTnFWwzQ==
     *    +     %2B
     *    = 	%3D
     *    /  	%2F
     */

    public static void main(String[] args) throws Exception {

        String uuid = getUUID();
        long timestamp = System.currentTimeMillis();
        String data = uuid + "jiahua" + timestamp;
        System.out.println(data);
        //数字签名加密
        String signature = signBase64(data, PRIVATE_KEY);
        //数字签名验证
        boolean verify = verifyBase64(data, PUBLIC_KEY, signature);
        System.out.println(verify);
        //System.out.println("http://thirdtest.kkcredit.cn:81/#/wcIndex/init?uuid="+uuid+"&source=jiahua&timestamp="+timestamp+"&signature="+URLEncoder.encode(signature, "utf-8"));
        System.out.println("http://third.kkcredit.cn/#/wcIndex/init?uuid="+uuid+"&source=jiahua&timestamp="+timestamp+"&signature="+URLEncoder.encode(signature, "utf-8"));
    }
    /**
     * 加密
     * data为uuid+source+timestamp参数组合字符串
     *
     * @param data       数据
     * @param privateKey 私钥
     */
    public static String signBase64(String data, String privateKey) throws Exception {
        //base64解密数据
        byte[] datas = data.getBytes("utf-8");
        //解密私钥
        byte[] keyBytes = Base64.decodeBase64(privateKey);
        //构造PKCS8EncodedKeySpec对象
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        //指定加密算法
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        //取私钥匙对象
        PrivateKey privateKey2 = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        //用私钥对信息生成数字签名
        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initSign(privateKey2);
        signature.update(datas);
        return Base64.encodeBase64String(signature.sign());
    }

    /**
     * 解密
     * data为uuid+source+timestamp参数组合字符串
     *
     * @param data      数据
     * @param publicKey 公钥
     * @param sign      签名字符串
     */
    public static boolean verifyBase64(String data, String publicKey, String sign) throws Exception {
        //base64解密数据
        byte[] datas = data.getBytes("utf-8");
        //解密公钥
        byte[] keyBytes = Base64.decodeBase64(publicKey);
        //构造X509EncodedKeySpec对象
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
        //指定加密算法
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        //取公钥匙对象
        PublicKey publicKey2 = keyFactory.generatePublic(x509EncodedKeySpec);
        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initVerify(publicKey2);
        signature.update(datas);
        //验证签名是否正常
        return signature.verify(Base64.decodeBase64(sign));
    }

    /**
     * 生成UUID
     *
     * @return
     */
    public static String getUUID() {
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        return uuid;
    }
}

